/*
 * @Author: Snow
 * @Date: 2021-10-20 09:56:27
 * @Description: 骨骼
 */

import { Matrix4 } from "../../utils/Matrix4";
import { Primitives } from "../../utils/Primitives";
import { TextrueUtil } from "../../utils/TextureUtil";
import { Util } from "../../utils/Util";
import { WebGLUtil } from "../../utils/WebGLUtil";
import { IProgramInfo } from "../interface/IDefine";
import { Render } from "../Render";
import { WebglTemplateBase } from "../template/WebglTemplateBase";

export class TextureBone1 extends WebglTemplateBase {

    private axisProgramInfo:IProgramInfo;

    protected override initProgram(): void {
        this.vsSource = `
        attribute vec4 a_position;
        attribute vec4 a_weight;
        attribute vec4 a_boneNdx;
        
        uniform mat4 projection;
        uniform mat4 view;
        uniform mat4 bones[4];
        
        void main() {
        
          gl_Position = projection * view *
                        (bones[int(a_boneNdx[0])] * a_position * a_weight[0] +
                         bones[int(a_boneNdx[1])] * a_position * a_weight[1] +
                         bones[int(a_boneNdx[2])] * a_position * a_weight[2] +
                         bones[int(a_boneNdx[3])] * a_position * a_weight[3]);
        //    gl_Position = projection * view * a_position;
        }
        `;

        this.fsSource = `
            precision mediump float;
            uniform vec4 color;
            void main () {
                gl_FragColor = color;
            }
        `;

        let vs2Source = `
            attribute vec4 a_position;

            uniform mat4 projection;
            uniform mat4 view;
            uniform mat4 model;
            
            void main() {
                gl_Position = projection * view * model * a_position;
            }
        `;
        super.initProgram();
        this.axisProgramInfo = WebGLUtil.createProgramInfo(Render.GL, vs2Source, this.fsSource);
    }

    protected override initBuffers(): void {
        //super.initBuffers();
        const gl = Render.GL;

        let arrays = {
            position: {
                numComponents: 2,
                data: [
                    0, 1,  // 0
                    0, -1,  // 1
                    2, 1,  // 2
                    2, -1,  // 3
                    4, 1,  // 4
                    4, -1,  // 5
                    6, 1,  // 6
                    6, -1,  // 7
                    8, 1,  // 8
                    8, -1,  // 9
                ],
            },
            boneNdx: {
                numComponents: 4,
                data: [
                    0, 0, 0, 0,  // 0
                    0, 0, 0, 0,  // 1
                    0, 1, 0, 0,  // 2
                    0, 1, 0, 0,  // 3
                    1, 0, 0, 0,  // 4
                    1, 0, 0, 0,  // 5
                    1, 2, 0, 0,  // 6
                    1, 2, 0, 0,  // 7
                    2, 0, 0, 0,  // 8
                    2, 0, 0, 0,  // 9
                ],
            },
            weight: {
                numComponents: 4,
                data: [
                    1, 0, 0, 0,  // 0
                    1, 0, 0, 0,  // 1
                    .5, .5, 0, 0,  // 2
                    .5, .5, 0, 0,  // 3
                    1, 0, 0, 0,  // 4
                    1, 0, 0, 0,  // 5
                    .5, .5, 0, 0,  // 6
                    .5, .5, 0, 0,  // 7
                    1, 0, 0, 0,  // 8
                    1, 0, 0, 0,  // 9
                ],
            },

            indices: {
                numComponents: 2,
                data: [
                    0, 1,
                    0, 2,
                    1, 3,
                    2, 3, //
                    2, 4,
                    3, 5,
                    4, 5,
                    4, 6,
                    5, 7, //
                    6, 7,
                    6, 8,
                    7, 9,
                    8, 9,
                ],
            },
        };

        let bufferInfo = WebGLUtil.createBufferInfoFromArrays(gl, arrays);

        // 4个矩阵, 每个骨骼一个
        var numBones = 4;
        var boneArray = new Float32Array(numBones * 16);

        var uniforms = {
            projection: Matrix4.orthographic(-20, 20, -10, 10, -1, 1),
            view: Matrix4.translation(-6, 0, 0),
            bones: boneArray,
            color: [1, 0, 0, 1],
        };

        // 为所有骨骼创建视图
        // 在一个数组中以便上传，但是是分割的
        // 数学计算用到的数组
        var boneMatrices = [];  // 全局变量数据
        var bones = [];         // 乘以绑定矩阵的逆之前的值
        var bindPose = [];      // 绑定矩阵
        for (var i = 0; i < numBones; ++i) {
            boneMatrices.push(new Float32Array(boneArray.buffer, i * 4 * 16, 16));
            bindPose.push(Matrix4.identity());  // 仅仅分配存储空间
            bones.push(Matrix4.identity());     // 仅仅分配存储空间
        }


        let computeBoneMatrices = (bones: any[], angle: number) => {
            var m = Matrix4.identity();
            bones[0] = Matrix4.rotateZ(angle);
            m = Matrix4.multiply(bones[0], Matrix4.translation(4, 0, 0));
            bones[1] = Matrix4.multiply(m, Matrix4.rotateZ(angle));
            m = Matrix4.multiply(bones[1], Matrix4.translation(4, 0, 0));
            bones[2] = Matrix4.multiply(m, Matrix4.rotateZ(angle));
            // bones[3]没有用
        }

        // 计算每个矩阵的初始位置
        computeBoneMatrices(bindPose, 0);

        // 计算他们的逆
        var bindPoseInv = bindPose.map(function (m) {
            return Matrix4.invert(m);
        });

        let drawScene = () => {
            let time = this.ts;
            time = time;
            WebGLUtil.resizeCanvasToMatchDisplaySize(gl);
            // Clear the canvas AND the depth buffer.
            //gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
            //gl.enable(gl.DEPTH_TEST);

            const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
            uniforms.projection = Matrix4.orthographic(-aspect * 10, aspect * 10, -10, 10, -1, 1);

            var t = time;
            var angle = Math.sin(t) * 0.8;
            computeBoneMatrices(bones, angle);

            // 每个都乘以绑定矩阵的逆
            bones.forEach(function (bone, ndx) {
                let m = Matrix4.multiply(bone, bindPoseInv[ndx]);
                for (let index = 0; index < m.length; index++) {
                    const element = m[index];
                    boneMatrices[ndx][index] = element;
                }
            });

            gl.useProgram(this.programInfo.program);
            // Setup all the needed buffers and attributes.
            WebGLUtil.setBuffersAndAttributes(gl, this.programInfo, bufferInfo);

            // Set the uniforms that are the same for all objects.
            WebGLUtil.setUniforms(this.programInfo, uniforms);

            // Draw the geometry.
            WebGLUtil.drawBufferInfo(gl, bufferInfo, gl.LINES);

            drawAxis(uniforms.projection, uniforms.view, bones);
        }
        this.draw = drawScene;

        var axisProgramInfo;
        var axisBufferInfo;
        let drawAxis = (projection, view, bones)=> {
            if (!axisProgramInfo) {
                axisProgramInfo = this.axisProgramInfo;
                axisBufferInfo = WebGLUtil.createBufferInfoFromArrays(gl, {
                    position: {
                        numComponents: 2,
                        data: [
                            0, 0,
                            1, 0,
                        ],
                    },
                });
            }

            var uniforms = {
                projection: projection,
                view: view,
                model:null,
                color:null,

            };

            gl.useProgram(axisProgramInfo.program);
            WebGLUtil.setBuffersAndAttributes(gl, axisProgramInfo, axisBufferInfo);

            for (var i = 0; i < 3; ++i) {
                drawLine(bones[i], 0, [0, 1, 0, 1]);
                drawLine(bones[i], Math.PI * -0.5, [0, 0, 1, 1]);
                //drawLine(bones[i], Math.PI * 0.6, [0, 0, 1, 1]);
            }

            function drawLine(mat, angle, color) {
                uniforms.model = Matrix4.multiply(mat,Matrix4.rotateZ(angle));
                uniforms.color = color;
                WebGLUtil.setUniforms(axisProgramInfo, uniforms);
                WebGLUtil.drawBufferInfo(gl, axisBufferInfo, gl.LINES);
            }
        }
    }
}